今天要聊到webpack另一個很實用的功能,當專案開發越來越龐大後,你會發現webpack build讓人真的多出很多發呆的時間,FB可以刷一陣子,所以可以hot reload變成一件很重要的事情,讓開發的流程可以更順暢,只要有程式碼變動,存檔的時候自動更新改動的部分。
Hot reload就是指說只更新有改動部分,不刷新整個頁面,也就是webpack指的HMR。
官網有一篇HMR詳細的文章,這邊就TL;DR。
它是一個用node.js express實作的開發環境伺服器,如果我們在開發時改動檔案,它會透過webpack-dev-middleware進行webpack compile,當compile完成後通知瀏覽器重新整理。它和CLI執行webpack不同的是,它不是實際build出來檔案,它會把bundle的結果先存在記憶體。
如同上面所說webpack-dev-server只是一個開發用的伺服器,webpack負責compile/bundle,而webpack-dev-middleware就是在中間負責溝通的中間件。Webpack就是使用這個webpack-dev-middleware來做hot reload。
可以參考Webpack Hot Middleware上面的說明:
Webpack hot reloading using only webpack-dev-middleware. This allows you to add hot reloading into an existing server without webpack-dev-server.
它是給webpack-dev-middleware使用的hot reload,簡單說我們可以使用webpack-dev-middleware加上webpack-hot-middleware實現hot reload的功能(不用使用webpack-dev-server)。
上面提到分成兩種使用方式,webpack-dev-server 或是 webpack-dev-middleware+webpack-hot-middleware,可以擇一就好,下面會提到兩種不同的使用方法。可以先參考
Webpack HMR Tutorial說明,或是stack overflow這篇,來區表兩則差別,選擇你想要的。目前在專案上我是採用webpack-dev-middleware+webpack-hot-middleware,第二種方式。
(1) 首先要npm install
npm install webpack-dev-server --save-dev
(2) 建立開發用的webpack.config.js檔 (或另取檔名webpack.config.dev.js)
module.exports = {
entry: [
'webpack/hot/dev-server',
'./main.js'
],
output: {
path: '/',
filename: 'bundle.js'
},
module: {
loaders: [
// 任何你需要的loaders
]
}
};
(3) 設定根目錄的html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
<!--最重要是加上這一行-->
<script src="http://localhost:8080/webpack-dev-server.js"></script>
<script src="bundle.js"></script>
</body>
</html>
(4) 在CLI上輸入指令
// webpack-dev-server 會建立localhost:8080的伺服器
// --devtool eval 建立原程式碼位置,當有錯誤可以找到原檔案與行數
// --progress 會顯示打包進度
// --colors 會幫 webpack 顯示的訊息加入顏色
// --hot 會把HotModuleReplacementPlugin到設定中
webpack-dev-server --devtool eval --progress --colors --hot
設定以上四個步驟,就可以在 http://localhost:8080/ 看到網站的樣子,可以改局部程式碼看看就會有變化。
這邊是使用webpack-dev-server inline mode的方式,還有用require('webpack-dev-server')的方式啟用,這邊就不做介紹,因為真的說太多太複雜了XD。可以參考官網 Webpack dev server了解更多。
(1) 首先要npm install
npm install webpack-dev-middleware webpack-hot-middleware --save-dev
(2) 建立開發用的webpack.config.js檔 (或另取檔名webpack.config.dev.js)
var webpack = require('webpack');
module.exports = {
entry: {
main: [
'main.js',
// reload=true,只說當有不能hot reload的情況,就整頁refresh
'webpack-hot-middleware/client?reload=true'
]
},
output: {
filename: 'bundle.js',
// compile後結果會存在記憶體中,直接設成根目錄
path: '/',
// 有require的靜態資源(例如:CSS),設完整路徑
publicPath: 'http://localhost:8080/'
},
module: {
loaders: [
// 任何你需要的loaders
]
},
plugins: [
// 提供hot reload功能
new webpack.HotModuleReplacementPlugin(),
// 當程式碼有錯誤時,不更新畫面,如果錯誤被修正才會hot reload
// 這個可以選擇使用。
new webpack.NoErrorsPlugin()
]
};
(3) 建立一個node.js Express程式
var express = require('express');
var webpack = require('webpack');
var webpackDevMiddleware = require('webpack-dev-middleware');
var webpackHotMiddleware = require('webpack-hot-middleware');
var webpackConfig = require('./webpack.config');
var app = express();
var port = 8080;
var compiler = webpack(webpackConfig);
app.use(webpackDevMiddleware(compiler, {
publicPath: webpackConfig.output.publicPath,
noInfo: true,
stats: {
colors: true
}
}));
app.use(webpackHotMiddleware(compiler));
app.get('/', function(req, res) {
var body = '<!doctype html>' +
'<html lang="en">'+
'<head><meta charset="utf-8"></head>' +
'<body>' +
'<script src="bundle.js"></script>' +
'</body>'+
'</html>';
res.writeHead(200, {"Content-Type": "text/html"});
res.write(body);
res.end();
});
app.listen(port, function(error) {
if (error) {
console.error(error);
} else {
console.info('==> ? Listening on port %s. Open up http://localhost:%s/ in your browser.', port, port);
}
});
(4) 在entry point加上HMR JavaScript API
這裏就是要在main.js最後面加上這一段,讓webpack知道這個檔案和他引用的檔案都可以被replace。這部分還有一些進階用法,因為沒有特別研究XD,所以就先放這段即可。
if (module.hot) {
module.hot.accept();
}
最後在CLI執行
node server.js
因為node.js不是很專業,這邊就不多解釋,一樣就可以在 http://localhost:8080/ 看到hot reload功能網站的樣子。
使用 Webpack 建立 React 專案開發環境
Webpack hmr tutorial
手把手深入理解 webpack dev middleware 原理與相關 plugins